#include "GameQuadrant.h"

GameQuadrant::GameQuadrant(
	WINAPP*  a_app,
	WINFPS*  a_fps,
	WINTIME* a_time,
	D3DF*    a_d3d,
	DINF*    a_din,
	char*    a_name,
	int      a_id,
	bool     a_renew)
{
	m_app  = a_app;
	m_fps  = a_fps;
	m_time = a_time;
	m_d3d  = a_d3d;
	m_din  = a_din;

	strcpy_s(m_name,32,a_name);
	m_selfId = a_id;
	m_swapId = a_id;
	m_completed = false;
	m_renew = a_renew;
}

void GameQuadrant::init()
{
	//create and set effect
	m_d3d->createEffect(&m_effect,"effects/ambient.fx");
	m_d3d->setEffect(&m_effect);

	//obtain system data
	m_sysData = (gData*)m_data;
	m_sysInfo = m_sysData->m_quads[m_selfId-GAMEQUADRANT];

	//init player and calc player position in quadrant space
	V3DF ppos(m_sysData->m_playerDir*(m_sysInfo->m_radius-(m_sysData->m_playerRad*2.0f)));
	V3DF prot(V3DF(0,m_sysData->m_playerRot,0));

	Physic_Object_Frame frame;
	frame.m_maxSpeed = 200.0f;
	frame.m_drag     = 25.0f;
	frame.m_radius   = m_sysData->m_playerRad;
	frame.m_position = V3DFToV3(ppos);

	m_player.init(FRAMEWORKS_MEM_REG,&m_world);
	m_player.initMesh("meshes/player.x",V3D_ZERO,V3D_ZERO,V3D_ONES,prot);
	m_player.initTexture("textures/tex_player.png");
	m_player.initPhysics(m_world.CreateObject(&frame));
	m_player.initShip(m_sysData->m_playerEnr);

	//create target plane
	m_target.init(FRAMEWORKS_MEM_REG);
	m_target.initMesh("meshes/plane.x",V3D_ZERO,V3D_ZERO,V3D_ONES*m_sysInfo->m_radius,V3D_ZERO);
	m_target.initTexture("textures/grid.png");
	m_target.update();

	//create player weapon
	gWeapon* wA = new gWeapon;
	wA->init(FRAMEWORKS_MEM_REG,&m_world);
	wA->initMesh("meshes/weapon.x",V3D_Z*100.0f,V3D_ZERO,V3D_ONES*0.5f,V3D_ZERO);
	wA->initTexture("textures/tex_weapon.png");
	wA->initWeapon(m_player.ptrTrn(),40.0f,&m_target);
	wA->initProjectile("meshes/sphere16.x","textures/starB.png",-1,2,600,10,&m_projList);

	gWeapon* wB = new gWeapon;
	wB->init(FRAMEWORKS_MEM_REG,&m_world);
	wB->initMesh("meshes/weapon.x",V3D_Z*100.0f,V3D_ZERO,V3D_ONES*0.5f,V3D_ZERO);
	wB->initTexture("textures/tex_weapon.png");
	wB->initWeapon(m_player.ptrTrn(),25.0f,&m_target);
	wA->initProjectile("meshes/sphere16.x","textures/starB.png",-1,2,600,10,&m_projList);

	m_player.initWeaponPri(wA);
	m_player.initWeaponSec(wB);

	//init camera
	m_camera.init(FRAMEWORKS_MEM_REG);
	m_camera.initCamera(V3D_ZERO,180.0f,-CAMR_ROT,WINW/WINH,CAMR_NER,CAMR_FAR);
	m_camera.setZMinMax(CAMR_ZMN,CAMR_ZMX);
	m_camera.setDis(CAMR_DIS);
	m_camera.trigMove();
	m_camera.attach(m_player.ptrTrn(),V3D_ZERO);

	//create enemies
	for(int i = 0; i < 10; i++)
	{
		Physic_Object_Frame eframe;
		eframe.m_maxSpeed = 100.0f;
		eframe.m_drag     = 25.0f;
		eframe.m_radius   = m_sysData->m_playerRad;
		eframe.m_position = V3DFToV3(V3D_ZERO);

		gEnemy* enemy = new gEnemy;
		enemy->init(FRAMEWORKS_MEM_REG,&m_world);
		enemy->initMesh("meshes/enemy.x",V3D_ZERO,V3D_ZERO,V3D_ONES,prot);
		enemy->initTexture("textures/tex_enemy.png");
		enemy->initPhysics(m_world.CreateObject(&eframe));
		enemy->initEnemy(&m_player);

		gWeapon* ew = new gWeapon;
		ew->init(FRAMEWORKS_MEM_REG,&m_world);
		ew->initMesh("meshes/sphere16.x",V3D_Z*100.0f,V3D_ZERO,V3D_ONES*0.25f,V3D_ZERO);
		ew->initTexture("textures/tex_weapon.png");
		ew->initWeapon(enemy->ptrTrn(),25.0f,&m_target);
		ew->initProjectile("meshes/sphere16.x","textures/starB.png",-1,2,600,10,&m_projList);

		enemy->initWeaponPri(ew);

		m_enemyList.insertToEnd(enemy);
	}

	//create and init stars
	char* starTex[3] = {"textures/starA.png","textures/starB.png","textures/starC.png"};
	for(int i = 0; i < m_sysInfo->m_starAmt; i++){
		Physic_Object_Frame tempFrame;
		tempFrame.m_radius   = m_sysInfo->m_starRad[i];
		tempFrame.m_position = Vector3(m_sysInfo->m_starPos[i].x,0,m_sysInfo->m_starPos[i].y);

		gObject *tempObj = new gObject;
		tempObj->init(FRAMEWORKS_MEM_REG,&m_world);
		tempObj->initMesh("meshes/sphere16.x",V3D_ZERO,V3D_ZERO,V3D_ONES,V3DF(randF(0,360),randF(0,360),randF(0,360)));
		tempObj->initTexture(starTex[randI(0,3)]);
		tempObj->initPhysics(m_world.CreateObject(&tempFrame));
		tempObj->update();

		m_objList.insertToEnd(tempObj);
	}

	//create and init planets
	char* planetTex[3] = {"textures/planetA.png","textures/planetB.png","textures/planetC.png"};
	for(int i = 0; i < m_sysInfo->m_planetAmt; i++){
		Physic_Object_Frame tempFrame;
		tempFrame.m_radius   = m_sysInfo->m_planetRad[i];
		tempFrame.m_position = Vector3(m_sysInfo->m_planetPos[i].x,0,m_sysInfo->m_planetPos[i].y);

		gObject *tempObj = new gObject;
		tempObj->init(FRAMEWORKS_MEM_REG,&m_world);
		tempObj->initMesh("meshes/sphere16.x",V3D_ZERO,V3D_ZERO,V3D_ONES,V3DF(randF(0,360),randF(0,360),randF(0,360)));
		tempObj->initTexture(planetTex[randI(0,3)]);
		tempObj->initPhysics(m_world.CreateObject(&tempFrame));
		tempObj->update();

		m_objList.insertToEnd(tempObj);
	}

	//create space stations
	Physic_Object_Frame tempFrame;
	tempFrame.m_radius   = 10.0f;
	tempFrame.m_position = Vector3(0,0,0);

	gObject *tempObj = new gObject;
	tempObj->init(FRAMEWORKS_MEM_REG,&m_world);
	tempObj->initMesh("meshes/station.x",V3D_ZERO,V3D_ZERO,V3D_ONES,V3DF(randF(0,360),randF(0,360),randF(0,360)));
	tempObj->initTexture("textures/tex_station.png");
	tempObj->initPhysics(m_world.CreateObject(&tempFrame));
	tempObj->update();

	m_objList.insertToEnd(tempObj);

	//init gui interface
	m_energy.init(FRAMEWORKS_MEM_REG);
	m_energy.initBar(
		"textures/health_back.png",
		"textures/health_bar.png",
		"textures/health_fore.png",
		V2DF(WINW-64,WINH-32),
		V2DF(7,-3));
	m_energy.setPerc(m_sysData->m_playerEnr.m_energyRem);

	m_shield.init(FRAMEWORKS_MEM_REG);
	m_shield.initSlider(
		"textures/slider_bar.png",
		"textures/slider_btn.png",
		"textures/icon_shield.png",
		"textures/info_shield.png",
		V2DF(WINW-244,WINH-94),
		V2DF(-2,-90),
		V2DF(72,-150));
	m_shield.update();
	m_shield.setPerc(m_sysData->m_playerEnr.m_energyShield);

	m_weapon.init(FRAMEWORKS_MEM_REG);
	m_weapon.initSlider(
		"textures/slider_bar.png",
		"textures/slider_btn.png",
		"textures/icon_weapon.png",
		"textures/info_weapon.png",
		V2DF(WINW-196,WINH-94),
		V2DF(-2,-90),
		V2DF(24,-150));
	m_weapon.update();
	m_weapon.setPerc(m_sysData->m_playerEnr.m_energyWeapon);

	m_boost.init(FRAMEWORKS_MEM_REG);
	m_boost.initSlider(
		"textures/slider_bar.png",
		"textures/slider_btn.png",
		"textures/icon_booster.png",
		"textures/info_booster.png",
		V2DF(WINW-148,WINH-94),
		V2DF(-2,-90),
		V2DF(-24,-150));
	m_boost.update();
	m_boost.setPerc(m_sysData->m_playerEnr.m_energyBoost);

	m_hyper.init(FRAMEWORKS_MEM_REG);
	m_hyper.initSlider(
		"textures/slider_bar.png",
		"textures/slider_btn.png",
		"textures/icon_hyper.png",
		"textures/info_hyper.png",
		V2DF(WINW-100,WINH-94),
		V2DF(-2,-90),
		V2DF(-72,-150));
	m_hyper.update();
	m_hyper.setPerc(m_sysData->m_playerEnr.m_energyHyper);

	m_gui.init(FRAMEWORKS_MEM_REG);
	m_guiInfo.init(FRAMEWORKS_MEM_REG);
	m_guiLog.init(FRAMEWORKS_MEM_REG);
	m_guiWeapons.init(FRAMEWORKS_MEM_REG);

	m_gui.initTexture("textures/gui.png",TEX_TL,V2D_ZERO,V2D_ONES,0.0f);
	m_guiInfo.initTexture("textures/info.png", TEX_TL, V2D_ZERO, V2D_ONES, 0.0f);
	m_guiLog.initTexture("textures/log.png", TEX_LC, V2DF(0,320), V2D_ONES, 0.0f);
	m_guiWeapons.initTexture("textures/weapons.png", TEX_BL, V2DF(0,720), V2D_ONES, 0.0f);

	m_gui.update();
	m_guiInfo.update();
	m_guiLog.update();
	m_guiWeapons.update();

	//init background
	m_grid.init(FRAMEWORKS_MEM_REG);
	m_grid.initMesh("meshes/plane.x",V3D_ZERO,V3D_Y*-GRID_DEP,V3D_ONES*m_sysInfo->m_radius*0.1f,V3D_ZERO);
	m_grid.initTexture("textures/grid.png");
	m_grid.update();

	m_circ.init(FRAMEWORKS_MEM_REG);
	m_circ.initMesh("meshes/plane.x",V3D_ZERO,V3D_Y*-8.0f,V3D_ONES*m_sysInfo->m_radius*0.1f,V3D_ZERO);
	m_circ.initTexture("textures/circleA.png");
	m_circ.update();

	for(int i = 0; i < 4; i++)
	{
		float dp = (STAR_SCL*(5.0f-(i+1.0f)))+STAR_SCL;
		float rt = 90.0f*i;

		m_back[i].init(FRAMEWORKS_MEM_REG);
		m_back[i].initMesh("meshes/plane.x",V3D_ZERO,V3DF(0,-dp,dp),
			V3D_ONES*STAR_SCL,V3DF(-CAMR_ROT,rt,0));
		m_back[i].initTexture("textures/stars.png");
		m_back[i].update();
	}
}

void GameQuadrant::reset()
{

}

void GameQuadrant::release()
{
	//release all memory
	m_enemyList.clearAll();
	m_objList.clearAll();
	m_projList.clearAll();

	m_world.Shutdown();
}

void GameQuadrant::input()
{
	//acquire input
	m_din->acquire();

	//perform input checking
	m_shield.input();
	m_weapon.input();
	m_boost.input();
	m_hyper.input();

	m_player.input();
	for(int i = 0; i < m_enemyList.getSizeUsed(); i++)
		m_enemyList.getIndex(i)->input();
	
	m_camera.input();
}

void GameQuadrant::update()
{
	//update world
	m_world.Update(m_time->getElapsed());

	//perform update
	guiUpdate();
	playerUpdate();
	collisionUpdate();

	for(int i = 0; i < m_enemyList.getSizeUsed(); i++)
		m_enemyList.getIndex(i)->update();

	for(int i = 0; i < m_objList.getSizeUsed(); i++)
		m_objList.getIndex(i)->update();

	//update camera
	m_camera.update();
}

void GameQuadrant::draw()
{
	m_d3d->drawBegin();

	//draw objects
	m_player.draw();

	for(int i = 0; i < m_enemyList.getSizeUsed(); i++)
		m_enemyList.getIndex(i)->draw();

	for(int i = 0; i < m_objList.getSizeUsed(); i++)
		m_objList.getIndex(i)->draw();

	for(int i = 0; i < m_projList.getSizeUsed(); i++)
		m_projList.getIndex(i)->draw();

	//draw back objects
	for(int i = 0; i < 4; i++)
		m_back[i].draw();
	m_grid.draw();
	m_circ.draw();

	//draw gui
	m_gui.draw();
	m_guiInfo.draw();
	m_guiLog.draw();
	m_guiWeapons.draw();

	m_energy.draw();
	m_shield.draw();
	m_weapon.draw();
	m_boost.draw();
	m_hyper.draw();

	//draw text
	m_d3d->drawText(m_name,V2D_ZERO,CL_RED);
	m_d3d->drawText("Hold SPACE at boundry to exit into GALAXY space",V2DF(0,16),CL_RED);

	m_d3d->drawEnd();
}

void GameQuadrant::pre()
{
	//update fps and time
	m_fps->update();
	m_time->update();
}

void GameQuadrant::post()
{
	if(m_player.getEnergy().m_energyRem < 0)
	{
		m_swapId = GAMECREDIT;
		m_completed = true;
	}
}

void GameQuadrant::guiUpdate()
{
	m_energy.setPerc(m_player.getEnergy().m_energyRem);

	m_energy.update();
	m_shield.update();
	m_weapon.update();
	m_boost.update();
	m_hyper.update();

	m_player.getEnergy().m_energyShield = m_shield.getPerc();
	m_player.getEnergy().m_energyWeapon = m_weapon.getPerc();
	m_player.getEnergy().m_energyBoost  = m_boost.getPerc();
	m_player.getEnergy().m_energyHyper  = m_hyper.getPerc();
}

void GameQuadrant::playerUpdate()
{
	//bounce player off quadrant radius
	float rad = m_player.getRad();
	V2DF  pos(m_player.getPos().x,m_player.getPos().z);
	V2DF  vel(m_player.getVel().x,m_player.getVel().z);
	if(pos.distance(V2D_ZERO)+rad > m_sysInfo->m_radius)
	{
		if(m_din->keyInput(KEY_SPACE))
		{
			m_sysData->m_playerEnr = m_player.getEnergy();
			m_sysData->m_playerDir = m_player.getPos().normal();
			m_sysData->m_playerRot = m_player.getRot().y;

			m_swapId = GAMEGALAXY;
			m_completed = true;
		}
		else
		{
			V2DF pA = nrCrPoint(V2D_ZERO,m_sysInfo->m_radius,pos);
			V2DF pB = nrCrPoint(pos,rad,pA);
			V2DF in = pB-pA;
			V2DF rf = ((in.perp().normal()*vel.dot(in.perp().normal()))*2.0f)-vel;

			V3DF p(pos.x,0,pos.y);
			V3DF i(in.x,0,in.y);
			V3DF v(rf.x,0,rf.y);

			m_player.setPos(p-i);
			m_player.setVel(v);

			m_player.getEnergy().m_energyRem -= 0.10f;
		}
	}

	//check for object collision
	for(int i = 0; i < m_objList.getSizeUsed(); i++)
	{
		gObject* obj = m_objList.getIndex(i);

		obj->update();
		if(m_player.getPhysics()->collide(obj->getPhysics()))
		{
			float radA = m_player.getRad();
			V2DF  posA(m_player.getPos().x,m_player.getPos().z);
			V2DF  velA(m_player.getVel().x,m_player.getVel().z);

			float radB = obj->getRad();
			V2DF  posB(obj->getPos().x,obj->getPos().z);

			V2DF pA = nrCrPoint(posB,radB,posA);
			V2DF pB = nrCrPoint(posA,radA,pA);
			V2DF in = pB-pA;
			V2DF rf = ((in.perp().normal()*velA.dot(in.perp().normal()))*2.0f)-velA;

			V3DF p(posA.x,0,posA.y);
			V3DF i(in.x,0,in.y);
			V3DF v(rf.x,0,rf.y);

			m_player.setPos(p-i);
			m_player.setVel(v);

			m_player.getEnergy().m_energyRem -= 0.01f;
		}
	}

	//update player object
	m_player.update();
}

void GameQuadrant::collisionUpdate()
{
	//check for projectile collisions
	//for(int i = 0; i < m_projList.getSizeUsed(); i++)
	//{
	//	gProjectile* proj = m_projList.getIndex(i);
	//	for(int j = 0; j < m_enemyList.getSizeUsed(); j++)
	//	{
	//		if(proj->getPos().distance(V3D_ZERO) > m_sysInfo->m_radius
	//			|| proj->getPhysics()->collide(m_enemyList.getIndex(j)->getPhysics()))
	//		{
	//			m_world.DestroyObject(m_enemyList.getIndex(j)->getPhysics());
	//			m_enemyList.removeFromIndex(j);
	//		}
	//	}
	//}

	for(int i = 0; i < m_projList.getSizeUsed(); i++)
	{
		gProjectile* proj = m_projList.getIndex(i);
		proj->update();
		if(proj->getPos().distance(V3D_ZERO) > m_sysInfo->m_radius)
		{
			m_world.DestroyObject(proj->getPhysics());
			m_projList.removeFromIndex(i);
			i--;
		}
	}

	for(int i = 0; i < m_projList.getSizeUsed(); i++)
	{
		bool hit = false;
		gProjectile* proj = m_projList.getIndex(i);
		for(int j = 0; j < m_objList.getSizeUsed(); j++)
		{
			gObject* obj = m_objList.getIndex(j);
			if(proj->getPhysics()->collide(obj->getPhysics()))
			{
				m_world.DestroyObject(obj->getPhysics());
				m_objList.removeFromIndex(j);
				j--;

				m_world.DestroyObject(proj->getPhysics());
				m_projList.removeFromIndex(i);
				i--;

				hit = true;
				break;
			}
		}

		if(hit) break;

		for(int j = 0; j < m_enemyList.getSizeUsed(); j++)
		{
			gEnemy* obj = m_enemyList.getIndex(j);
			if(proj->getPhysics()->collide(obj->getPhysics()))
			{
				m_world.DestroyObject(obj->getPhysics());
				m_enemyList.removeFromIndex(j);
				j--;

				m_world.DestroyObject(proj->getPhysics());
				m_projList.removeFromIndex(i);
				i--;

				break;
			}
		}
	}

	//for(int i = 0; i < m_projList.getSizeUsed(); i++)
	//{
	//	gProjectile* proj = m_projList.getIndex(i);
	//	proj->update();
	//	if(proj->getPhysics()->collide())
	//	{
	//		m_world.DestroyObject(proj->getPhysics());
	//		m_projList.removeFromIndex(i);
	//		i--;
	//	}
	//}
}